﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;

using MyLibrary.ThreeLayer.DataAccess.KeyGenerator;
using MyLibrary.ThreeLayer.DataAccess.CustomException;
using MyLibrary.ThreeLayer.Utility;
using MyLibrary.ThreeLayer.DataAccess.MetaData;
using MyLibrary.ThreeLayer.DataAccess.QueryLanguage;
using MyLibrary.ThreeLayer.DataAccess.Enum;
using MyLibrary.ThreeLayer.DataAccess.Interface;

namespace MyLibrary.ThreeLayer.DataAccess
{
    internal abstract class DBProvider : Transaction, IDbProvider, ITransaction, ICloseRequire
    {
        protected DBProvider()
        {
        }

        public void Close()
        {
            if (base._innerConnection != null && base._innerConnection.State != ConnectionState.Closed)
                base._innerConnection.Close();
        }

        public abstract IDbDataAdapter CreateAdapter();
        public abstract IDbCommand CreateCommand;
        public ISQLCommandBuilder<T> CreateCommandBuilder<T>() where T : class, new()
        {

        }

        public abstract IDataParameter CreateParameter();
        public IDbConnection GetConnection()
        {
            return base._innerConnection;
        }

        public abstract void OpenConnection(string connectionString);
        public abstract ProviderType ProviderType { get; }
    }

    public class ProviderFactory
    {
        public static IDbProvider CreateProvider()
        {
            
        }
    }

    internal class ProviderSession : Transaction, ISession
    {
        protected IDbProvider _dbProvider = null;

        public ProviderSession(IDbProvider provider)
        {
            this._dbProvider = provider;
        }

        public void Close()
        {
            this._dbProvider.Close();
        }

        #region IBaseSession Members

        public int Delete<T>(T o) where T : class, new()
        {
            MappingCollection collection = MetaDataFactory.GetMappingCollection(typeof(T));
            return this._dbProvider.CreateCommandBuilder<T>().BuildDeleteCommand(this._dbProvider, collection, o).ExecuteNonQuery();
        }

        public int Delete<T>() where T : class, new()
        {
            MappingCollection collection = MetaDataFactory.GetMappingCollection(typeof(T));
            return this._dbProvider.CreateCommandBuilder<T>().BuildDeleteCommand(this._dbProvider, collection).ExecuteNonQuery();
        }

        public T Get<T>(object keys) where T : class, new()
        {
            MappingCollection collection = MetaDataFactory.GetMappingCollection(typeof(T));
            IList<MappingField> keyFields = collection.GetKeyFields();
            if (keyFields.Count == 0)
                throw new MappingException("实体类型中不包括主键", typeof(T));
            if (keyFields.Count > 1)
                throw new MappingException("只支持一个标示域", typeof(T));

            IDataReader reader = this._dbProvider.CreateCommandBuilder<T>().BuildQueryCommand(this._dbProvider, collection, keyFields[0], keys).ExecuteReader();

            T local = default(T);
            if (reader.Read())
                local = new FullMatchEntityMapper<T>().ToEntity(reader, collection);
            reader.Close();
            return local;
        }

        public int Insert<T>(T obj) where T : class, new()
        {
            MappingCollection collection = MetaDataFactory.GetMappingCollection(typeof(T));
            IList<MappingField> identityFields = collection.GetKeyFields();
            if (identityFields.Count > 1)
                throw new MappingException("只支持一个标示域", typeof(T));

            KeyGeneratorFactory.GenerateKey(obj, collection);
            ISQLCommandBuilder<T> builder = this._dbProvider.CreateCommandBuilder<T>();
            IDbCommand command = builder.BuildInsertCommand(this._dbProvider, collection, obj);
            int num = 0;

            if (identityFields.Count == 0)
                return command.ExecuteNonQuery();
            IDbCommand command2 = builder.BuildQueryCommand(this._dbProvider, collection, obj);
            num = command2.ExecuteNonQuery();
            object obj2 = command2.ExecuteScalar();
            identityFields[0].SetValue(obj, obj2);
            return num;
        }
        
        public bool Load<T>(T obj) where T : class, new()
        {
            MappingCollection collection = MetaDataFactory.GetMappingCollection(typeof(T));
            IList<MappingField> keyFields = collection.GetKeyFields();
            if (keyFields.Count == 0)
                throw new MappingException("实体类型中不包括主键", typeof(T));
            IDataReader reader = this._dbProvider.CreateCommandBuilder<T>().BuildQueryCommand(this._dbProvider, collection, keyFields, obj).ExecuteReader();
            bool flag = false;
            if (reader.Read())
                flag = true;
            reader.Close();
            return flag;
        }

        public IList<T> LoadAll<T>(T obj) where T : class, new()
        {
            MappingCollection collection = MetaDataFactory.GetMappingCollection(typeof(T));
            IDataReader reader = this._dbProvider.CreateCommandBuilder<T>().BuildQueryCommand(this._dbProvider, collection).ExecuteReader();
            IList<T> list = new FullMatchEntityMapper<T>().ToEntities(reader, collection);
            reader.Close();
            return list;
        }

        public int Save<T>(T obj) where T : class, new()
        {
            if (this.Load<T>(obj))
                return this.Update<T>(obj);
            return this.Insert<T>(obj);
        }

        public int Update<T>(T obj) where T : class, new()
        {
            MappingCollection collection = MetaDataFactory.GetMappingCollection(typeof(T));
            return this._dbProvider.CreateCommandBuilder<T>().BuildUpdateCommand(this._dbProvider, collection, obj).ExecuteNonQuery();
        }

        #endregion

        #region IRelationSession Members

        public int Delete<T>(T obj, bool deleteRef) where T : class, new()
        {
            if (!deleteRef)
                return this.Delete<T>(obj);

            IList<MappingField> keyFields = MetaDataFactory.GetMappingCollection(obj.GetType()).GetKeyFields();
            if (keyFields.Count == 0)
                throw new MappingException("关联删除需要提供主键", typeof(T));
            if (keyFields.Count > 1)
                throw new MappingException("关联删除的主键只能有一个", typeof(T));

            object keyValue = keyFields[0].GetValue(obj);
            return this.Delete(typeof(T), keyValue, deleteRef);
        }

        public int Delete(Type t, object keyValue, bool delRef)
        {
            MappingCollection collection = MetaDataFactory.GetMappingCollection(t);
            ISQLCommandBuilder<object> builder = this._dbProvider.CreateCommandBuilder<object>();
            IDbCommand command = null;

            if (delRef)
                command = builder.BuildDeleteCommand(this._dbProvider, collection, keyValue);
            else
                command = builder.BuildDeleteCommand(this._dbProvider, collection, keyValue);
            return command.ExecuteNonQuery();
        }

        public int DeleteRef(object obj1, object obj2)
        {
            return this._dbProvider.CreateCommandBuilder<object>().BuildDeleteCommand(this._dbProvider, obj1, obj2).ExecuteNonQuery();
        }

        public T GetRef<T>(object obj) where T : class, new()
        {
            MappingField refField = MetaDataFactory.GetMappingCollection(obj.GetType()).GetRefField(typeof(T));
            if (refField == null)
                throw new ArgumentNullException("不存在关联关系");
            object keyValue = refField.GetValue(obj);
            if (keyValue == null)
                return default(T);
            return this.Get<T>(keyValue);
        }

        public List<T> GetRefList<T>(object obj) where T : class, new()
        {
            MappingCollection collection = MetaDataFactory.GetMappingCollection(typeof(T));
            MappingCollection refCollection = MetaDataFactory.GetMappingCollection(obj.GetType());

            IList<MappingField> keyFields = collection.GetKeyFields();
            if (keyFields == null)
                throw new MappingException("不存在主键域");
            object keyValue = keyFields[0].GetValue(obj);
            MappingField refField = refCollection.GetRefField(obj.GetType());
            IDataReader reader = this._dbProvider.CreateCommandBuilder<T>().BuildQueryCommand(this._dbProvider, refCollection, refField, keyValue).ExecuteReader();
            IList<T> list = new FullMatchEntityMapper<T>().ToEntities(reader, refCollection);
            reader.Close();
            return list;
        }

        public int SaveRef(object obj1, object obj2)
        {
            return this._dbProvider.CreateCommandBuilder<object>().BuildInsertCommand(this._dbProvider, obj1, obj2).ExecuteNonQuery();
        }

        #endregion

        #region IConditionSession Members

        public int Delete<T>(ConditionExpression condition) where T : class, new()
        {
            MappingCollection collection = MetaDataFactory.GetMappingCollection(typeof(T));
            return this._dbProvider.CreateCommandBuilder<T>().BuildDeleteCommand(this._dbProvider, collection, condition).ExecuteNonQuery();
        }

        public T Get<T>(ConditionExpression condition) where T : class, new()
        {
            MappingCollection collection = MetaDataFactory.GetMappingCollection(typeof(T));
            IDataReader reader = this._dbProvider.CreateCommandBuilder<T>().BuildQueryCommand(this._dbProvider, collection, collection).ExecuteReader();

            T local = default(T);
            if (reader.Read())
                local = new FullMatchEntityMapper<T>().ToEntity(reader, collection);
            reader.Close();
            return local;
        }

        public IList<T> JoinQuery<T>(ConditionExpression condition) where T : class, new()
        {
            MappingCollection collection = MetaDataFactory.GetMappingCollection(typeof(T));
            IDataReader reader = this._dbProvider.CreateCommandBuilder<T>().BuildJoinQueryCommand(this._dbProvider, collection, condition).ExecuteReader();
            IList<T> list = null;
            list = new FullMatchEntityMapper<T>().ToEntities(reader, collection);
            reader.Close();
            return list;
        }

        public IList<T> Query<T>(ConditionExpression condition) where T : class, new()
        {
            MappingCollection collection = MetaDataFactory.GetMappingCollection(typeof(T));
            IDataReader reader = this._dbProvider.CreateCommandBuilder<T>().BuildQueryCommand(this._dbProvider, collection, condition).ExecuteReader();
            IList<T> list = null;

            list = new FullMatchEntityMapper<T>().ToEntities(reader, collection);
            reader.Close();
            return list;
        }

        public IList<T> Query<T>(QueryExpression query) where T : class, new()
        {
            MappingCollection collection = MetaDataFactory.GetMappingCollection(typeof(T));
            IDataReader reader = this._dbProvider.CreateCommandBuilder<T>().BuildQueryCommand(this._dbProvider, query).ExecuteReader();
            IList<T> list = null;

            list = new FullMatchEntityMapper<T>().ToEntities(reader, collection);
            reader.Close();
            return list;
        }

        public DataSet QueryDataSet(params QueryExpression[] querys)
        {
            if (querys == null || querys.Length == 0)
                return null;

            ISQLCommandBuilder<object> builder = this._dbProvider.CreateCommandBuilder<object>();
            IDbCommand command = null;

            if (querys.Length == 1)
                command = builder.BuildQueryCommand(this._dbProvider, querys[0]);
            else
            {
                command = this._dbProvider.CreateCommand();
                foreach (QueryExpression q in querys)
                {
                    if (!String.IsNullOrEmpty(command.CommandText))
                        command.CommandText = command.CommandText + ";";
                    IDbCommand command2 = builder.BuildQueryCommand(this._dbProvider, q);
                    command.CommandText = command.CommandText + command2.CommandText;
                    foreach (IDataParameter parameter in command2.Parameters)
                        command2.Parameters.Add(parameter);
                }
            }

            IDbDataAdapter adapter = this._dbProvider.CreateAdapter();
            adapter.SelectCommand = command;
            DataSet ds = new DataSet();
            adapter.Fill(ds);
            return ds;
        }

        public DataTable QueryDataTable<T>(ConditionExpression query) where T : class, new()
        {
            MappingCollection collection = MetaDataFactory.GetMappingCollection(typeof(T));
            IDbCommand command = this._dbProvider.CreateCommandBuilder<T>().BuildQueryCommand(this._dbProvider, collection, query);
            IDbDataAdapter adapter = this._dbProvider.CreateAdapter();
            adapter.SelectCommand = command;
            DataSet ds = new DataSet();
            adapter.Fill(ds);
            return ds.Tables[0];
        }

        public int Update<T>(T obj, ConditionExpression condition) where T : class, new()
        {
            MappingCollection collection = MetaDataFactory.GetMappingCollection(typeof(T));
            return this._dbProvider.CreateCommandBuilder<T>().BuildUpdateCommand(this._dbProvider, collection, obj, condition).ExecuteNonQuery();
        }

        public int Update<T>(T obj, ConditionExpression condition, IQueryField[] fields) where T : class, new()
        {
            MappingCollection collection = MetaDataFactory.GetMappingCollection(typeof(T));
            return this._dbProvider.CreateCommandBuilder<T>().BuildUpdateCommand(this._dbProvider, collection, obj, condition, fields).ExecuteNonQuery();
        }

        #endregion
    }

}
